<?php

/**
 * contact : 刘经理 19326416371
 * company : 版权所属 四川北星惯牌科技有限公司
 **/

namespace app\common\manager\assistant;

use app\common\constant\Constant;
use app\common\manager\BaseManager;
use app\common\model\assistant\Account;
use app\common\model\assistant\Bill;
use app\common\model\assistant\Moneylog;
use app\common\model\Config;
use app\common\model\User;
use think\Db;
use think\Exception;

class AssistantAccountManager extends BaseManager
{
    CONST TYPE_FREEZE = 1;
    CONST TYPE_FREEZE_MESSAGE = '冻结';
    CONST TYPE_WITHDRAWAL = 2;
    CONST TYPE_WITHDRAWAL_MESSAGE = '提现';
    CONST TYPE_TEAM = 3;
    CONST TYPE_TEAM_MESSAGE = '组队';
    CONST TYPE_FREEZE_RETURN = 4;
    CONST TYPE_FREEZE_RETURN_MESSAGE = '解冻';

    /* CONST TYPE_TEAM_REBATE = 11;
     CONST TYPE_TEAM_REBATE_MESSAGE = '组队返点';*/

    CONST TYPE_MONEY_ARRAY = [

        self::TYPE_FREEZE => [
            'value' => self::TYPE_FREEZE,
            'memo' => self::TYPE_FREEZE_MESSAGE,
        ],

        self::TYPE_WITHDRAWAL => [
            'value' => self::TYPE_WITHDRAWAL,
            'memo' => self::TYPE_WITHDRAWAL_MESSAGE,
        ],

        self::TYPE_TEAM => [
            'value' => self::TYPE_TEAM,
            'memo' => self::TYPE_TEAM_MESSAGE,
        ],


        self::TYPE_FREEZE_RETURN => [
            'value' => self::TYPE_FREEZE_RETURN,
            'memo' => self::TYPE_FREEZE_RETURN_MESSAGE,
        ]
    ];

    CONST CHANGE_TYPE_PAYMENT=1;
    CONST CHANGE_TYPE_PAYMENT_MESSAGE='支出';
    CONST CHANGE_TYPE_INCOME = 2;
    CONST CHANGE_TYPE_INCOME_MESSAGE = '收入';

    CONST CHANGE_TYPE_ARRAY = [
        self::CHANGE_TYPE_PAYMENT=>[
            'value'=>self::CHANGE_TYPE_PAYMENT,
            'memo'=>self::CHANGE_TYPE_PAYMENT_MESSAGE,
        ],
        self::CHANGE_TYPE_INCOME=>[
            'value'=>self::CHANGE_TYPE_INCOME,
            'memo'=>self::CHANGE_TYPE_INCOME_MESSAGE,
        ]
    ];
    public static function getAccount($assistantId,$uid)
    {
        try {
            $assistantAccount = Account::where('assistant_id',$assistantId)->where('user_id',$uid)->find();
            unset($assistantAccount->id);
            unset($assistantAccount->user_id);
            unset($assistantAccount->status);
            return ['code'=>self::$successCode,'message'=>self::$successMessage,'data'=>$assistantAccount];
        }catch (Exception $exception){
            return ['code'=>self::$failCode,'message'=>$exception->getMessage()];
        }
    }

    /**
     * 为助教创建账户
     * @param int $userId
     * @param int $assistantId
     * @param bool $trans
     * @return array
     */
    public static function account(int $userId,int $assistantId,bool $trans=true):array
    {
        $assistantAccount = null;
        if ($trans)
            Db::startTrans();
        try {
            if (!Account::where('user_id',$userId)->where('assistant_id',$assistantId)->find()) {
                $assistantAccount = Account::create([
                    'user_id'=>$userId,
                    'assistant_id'=>$assistantId
                ]);
            }
            $assistantAccount = Account::where('user_id',$userId)->where('assistant_id',$assistantId)->find();
            if ($trans)
                Db::commit();
            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
            self::setData($assistantAccount);
        }catch (Exception $exception){
            if ($trans)
                Db::rollback();
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage());
        }

        return ['code'=>self::getStatusCode(),'message'=>self::getMessage(),'data'=>self::getData()];
    }

    /**
     * 账户金额变动
     * @param int $assistantId  助教id
     * @param int $userId  用户uid
     * @param float $money 金额
     * @param int $outIn 1=支出,2=收入
     * @param int $datetime 时间戳
     * @param int $detail 1=冻结,2=提现,3=组队,4=解冻
     * @param array $extend [扩展字段]['relation_id'=>$relation_id,'relation_order'=>$relation_order]  relation_id 相关id  relation_order 相关订单号
     * @param boolean $trans 是否开启事务
     * @return array
     */
    public static function money(int $assistantId,int $userId,float $money,int $outIn,int $datetime,int $detail,array $extend=[],bool $trans=true):array
    {
        //file_put_contents('recharge.txt','func:'.json_encode(func_get_args()),FILE_APPEND);
        $datetime = date('Y-m-d H:i:s',$datetime);
        $result = ['code'=>self::$failCode,'message'=>self::$failMessage];
        if ($trans)
            Db::startTrans();
        try {
            $userInfo = User::get($userId);
            $assistantAccount = Account::where(['assistant_id'=>$assistantId,'user_id'=>$userId])->find();
            if(!$assistantAccount){
                $accountResult = self::account($userId,$assistantId);
                if ($accountResult['code']==self::$failCode){
                    throw new Exception($accountResult['message']);
                }
                $assistantAccount = $accountResult['data'];
            }
            switch ($detail){
                case self::TYPE_FREEZE:
                    if(!Account::where('assistant_id',$assistantId)
                        ->where('user_id',$userId)
                        ->where('total','>=',$money)
                        ->where('available','>=',$money)
                        ->where('version',$assistantAccount->version)
                        ->update([
                            'available' => Db::raw('available - '.$money),
                            'freeze' => Db::raw('freeze + '.$money),
                            'version' => Db::raw('version + 1'),
                        ])){
                        throw new Exception('账户余额变动失败');
                    }

                    $message = sprintf(AssistantMoneyManager::TYPE_FREEZE_MESSAGE,$userInfo->username,$datetime,$money);
                    $result = AssistantMoneyManager::UserMoneyLog($assistantAccount,$userId,$money,0,AssistantMoneyManager::TYPE_FREEZE,$message,$extend,false);
                    break;

                case self::TYPE_WITHDRAWAL:
                    if(!Account::where('assistant_id',$assistantId)
                        ->where('user_id',$userId)
                        ->where('freeze','>=',$money)
                        ->where('total','>=',$money)
                        ->where('version',$assistantAccount->version)
                        ->update([
                            'total' => Db::raw('total - '.$money),
                            'freeze' => Db::raw('freeze - '.$money),
                            'withdraw' => Db::raw('withdraw + '.$money),
                            'version' => Db::raw('version + 1'),
                        ])){
                        throw new Exception('账户余额变动失败');
                    }

                    $message = sprintf(AssistantMoneyManager::TYPE_WITHDRAWAL_MESSAGE,$userInfo->username,$datetime,$money);
                    $result = AssistantMoneyManager::UserMoneyLog($assistantAccount,$userId,-$money,AssistantMoneyManager::TYPE_DECREASE,AssistantMoneyManager::TYPE_WITHDRAWAL,$message,$extend,false);
                    break;
                case self::TYPE_TEAM:
                    if ($outIn==self::CHANGE_TYPE_PAYMENT){
                        if(!Account::where('assistant_id',$assistantId)
                            ->where('user_id',$userId)
                            ->where('available','>=',$money)
                            ->where('version',$assistantAccount->version)
                            ->update([
                                'total' => Db::raw('total - '.$money),
                                'available' => Db::raw('available - '.$money),
                                'version' => Db::raw('version + 1')
                            ])){
                            throw new Exception('账户余额变动失败');
                        }
                        $message = sprintf(AssistantMoneyManager::TYPE_DECREASE_TEAM_MESSAGE,$userInfo->username,$datetime,$money);
                        $result = AssistantMoneyManager::UserMoneyLog($assistantAccount,$userId,-$money,AssistantMoneyManager::TYPE_DECREASE,AssistantMoneyManager::TYPE_TEAM,$message,$extend,false);
                    }else if ($outIn==self::CHANGE_TYPE_INCOME){
                        if(!Account::where('assistant_id',$assistantId)
                            ->where('user_id',$userId)
                            ->where('version',$assistantAccount->version)
                            ->update([
                                'total' => Db::raw('total + '.$money),
                                'available' => Db::raw('available + '.$money),
                                'income_sum' => Db::raw('income_sum + '.$money),
                                'version' => Db::raw('version + 1')
                            ]))
                        {
                            throw new Exception('账户余额变动失败');
                        }
                        $message = sprintf(AssistantMoneyManager::TYPE_INCREASE_TEAM_MESSAGE,$userInfo->username,$datetime,$money);
                        $result = AssistantMoneyManager::UserMoneyLog($assistantAccount,$userId,$money,AssistantMoneyManager::TYPE_INCREASE,AssistantMoneyManager::TYPE_TEAM,$message,$extend,false);
                    }

                    break;
                case self::TYPE_FREEZE_RETURN:

                    if(!Account::where('assistant_id',$assistantId)
                        ->where('user_id',$userId)
                        ->where('freeze','>=',$money)
                        ->where('version',$assistantAccount->version)
                        ->update([
                            'freeze' => Db::raw('freeze - '.$money),
                            'available' => Db::raw('available + '.$money),
                            'version' => Db::raw('version + 1'),
                        ])){
                        throw new Exception('账户余额变动失败');
                    }

                    $message = sprintf(AssistantMoneyManager::TYPE_UNFREEZE_RETURN_MESSAGE,$userInfo->username,$datetime,$money);
                    $result = AssistantMoneyManager::UserMoneyLog($assistantAccount,$userId,$money,0,AssistantMoneyManager::TYPE_UNFREEZE_RETURN,$message,$extend,false);
                    break;
                default:
                    break;


            }
            if ($result['code']==self::$failCode){
                throw new Exception($result['message']);
            }

            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
            if ($trans)
                Db::commit();
        }catch (Exception $exception){
            if ($trans)
                Db::rollback();
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage().$exception->getLine());
        }

        return ['code'=>self::getStatusCode(),'message'=>self::getMessage()];
    }



    /**
     * 获取金额日志
     * @param int $assistantId
     * @param int $userId
     * @param int $type
     * @param int $detail
     * @param array $where
     * @param int $page
     * @param int $step
     * @return array
     */
    public static function moneyLog(int $assistantId,int $userId,int $type=0,int $detail=0,array $where = [],int $page=1,int $step=Constant::PAGE_LIMIT):array
    {
        $return = ['total'=>0,'totalPage'=>1,'currentPage'=>$page,'list'=>[]];
        try {
            $start = ($page-1)*$step;
            $total = Moneylog::where('assistant_id',$assistantId)->where('user_id',$userId)->where(function ($query) use ($type) {
                if ($type){
                    return $query->where('type',$type);
                }
            })->where(function ($query) use ($detail) {
                if ($detail){
                    return $query->where('detail',$detail);
                }
            })->where(function ($query) use ($where) {
                if ($where){
                    return $query->where($where);
                }
            })->count();

            $data  = Moneylog::where('assistant_id',$assistantId)->where('user_id',$userId)->where(function ($query) use ($type) {
                if ($type){
                    return $query->where('type',$type);
                }
            })->where(function ($query) use ($detail) {
                if ($detail){
                    return $query->where('detail',$detail);
                }
            })->where(function ($query) use ($where) {
                if ($where){
                    return $query->where($where);
                }
            })->limit($start,$step)->order('id desc')->select();

            if ($data){
                foreach ($data as $k=>&$v){
                    $v['type_name'] = self::CHANGE_TYPE_ARRAY[$v['type']]['memo'] ?? '不详';
                    $v['detail_name'] = self::TYPE_MONEY_ARRAY[$v['detail']]['memo'] ?? '不详';
                }
            }
            $page = page($total,$step,$page);
            $return['list'] = $data;
            $return = array_merge($return,$page);
            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
            self::setData($return);
        }catch (Exception $exception){
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage());
        }
        return ['code'=>self::getStatusCode(),'message'=>self::getMessage(),'data'=>$return];
    }

    /**
     * 助教账户提现
     * @param $assistantId
     * @param $userId
     * @param $money
     * @param $type
     * @param $trans
     * @return array
     */
    public static function withdrawMoney($assistantId,$userId,$money,$type='wechat',$trans=true):array
    {
        if ($trans){
            Db::startTrans();
        }
        try {
            $singleWithdrawLimit = Config::where('name','single_withdraw_amount_limit')->value('value');
            $singleDayLimit = Config::where('name','single_day_withdraw_limit')->value('value');
            $single_withdraw_min = Config::where('name','single_withdraw_min')->value('value');
            if ($money < $single_withdraw_min){
                throw new Exception('单笔最小金额为:'.$single_withdraw_min);
            }

            if ($money > $singleWithdrawLimit){
                throw new Exception('单笔最大金额为:'.$singleWithdrawLimit);
            }
            $todayStartTime = strtotime(date('Y-m-d H:i:s',time()));
            $todayEndTime = strtotime(date('Y-m-d 23:59:59',time()));
            $todayWithdrawAmount = \app\common\model\assistant\Withdraw::where('assistant_id',$assistantId)->where('user_id',$userId)->where('status',1)->where('create_time','between time',[$todayStartTime,$todayEndTime])->where('status','<>',\app\common\model\assistant\Withdraw::STATUS_BACK)->sum('amount');;
            if (bcadd($todayWithdrawAmount,$money,2) > $singleDayLimit){
                throw new Exception('已超过今日限额:'.$singleDayLimit);
            }
            $orderId = orderNum();
            $withdrawOrder = [
                'order'=>$orderId,
                'assistant_id'=>$assistantId,
                'user_id'=>$userId,
                'type'=>$type,
                'amount'=>$money,
                'create_time'=>time()
            ];
            $withdrawOrderInfo = \app\common\model\assistant\Withdraw::create($withdrawOrder);
            if (!$withdrawOrderInfo){
                throw new Exception('提现订单创建失败');
            }

            $result = self::money($assistantId,$userId,$money,0,time(),self::TYPE_FREEZE,['relation_id'=>$withdrawOrderInfo->id,'relation_order'=>$orderId],false);
            if ($result['code']!=self::$successCode) {
                throw new Exception($result['message']);
            }
            if ($trans){
                Db::commit();
            }
            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
        }catch (Exception $exception){
            if ($trans){
                Db::rollback();
            }
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage());
        }
        return ['code'=>self::getStatusCode(),'message'=>self::getMessage()];
    }

    /**
     * 获取助教提现列表
     * @param $assistantId
     * @param $userId
     * @param $page
     * @param $step
     * @return array
     */
    public static function getWithdrawList($assistantId,$userId,$page=1,$step=Constant::PAGE_LIMIT):array
    {
        $return = ['total' => 0, 'totalPage' => 1, 'currentPage' => $page, 'list' => []];
        try {
            $start = ($page - 1) * $step;
            $total = \app\common\model\assistant\Withdraw::where('assistant_id', $assistantId)->where('user_id', $userId)->count();
            $data = \app\common\model\assistant\Withdraw::where('assistant_id', $assistantId)->where('user_id', $userId)->limit($start, $step)->order('id desc')->select();
            if ($data) {
                foreach ($data as $k => &$v) {
                    $v['status_name'] = \app\common\model\assistant\Withdraw::STATUS_ARRAY[$v['status']];
                    $v['type_name'] = \app\common\model\assistant\Withdraw::TYPE_ARRAY[$v['type']];
                }
            }
            $page = page($total, $step, $page);
            $return['list'] = $data;
            $return = array_merge($return, $page);
            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
            self::setData($return);
        } catch (Exception $exception) {
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage());
        }
        return ['code' => self::getStatusCode(), 'message' => self::getMessage(), 'data' => $return];
    }

    /**
     * 获取账单列表
     * @param $assistantId
     * @param $userId
     * @param $time
     * @param $type
     * @param $page
     * @param $step
     * @return array
     */
    public static function getBillList($assistantId,$userId,$time,$type=Bill::TYPE_DAY,$page=1,$step=Constant::PAGE_LIMIT):array
    {
        $return = ['total'=>0,'totalPage'=>1,'currentPage'=>$page,'info'=>[],'list'=>[]];
        try {
            $totalInfo = Bill::where('assistant_id', $assistantId)
                ->where('user_id', $userId)
                ->where(function ($query) use ($time,$type) {
                    if ($type == Bill::TYPE_DAY){
                        $query->where('year', date('Y',strtotime($time)))->where('month', date('m',strtotime($time)))->where('day',date('d',strtotime($time)))->where('type',Bill::TYPE_DAY);
                    }else if ($type == Bill::TYPE_MONTH){
                        $query->where('year', date('Y',strtotime($time)))->where('month', date('m',strtotime($time)))->where('type',Bill::TYPE_MONTH);
                    }else if ($type == Bill::TYPE_YEAR){
                        $query->where('year', date('Y',strtotime($time)))->where('type',Bill::TYPE_YEAR);
                    }
                })->find();

            $total = Bill::where('assistant_id', $assistantId)
                ->where('user_id', $userId)
                ->where(function ($query) use ($time,$type) {
                    if ($type == Bill::TYPE_MONTH){
                        $query->where('year', date('Y',strtotime($time)))->where('month', date('m',strtotime($time)))->where('type',Bill::TYPE_DAY);
                    }else if ($type == Bill::TYPE_YEAR){
                        $query->where('year', date('Y',strtotime($time)))->where('type',Bill::TYPE_MONTH);
                    }
                })
                ->count();
            $data = Bill::where('assistant_id', $assistantId)
                ->where('user_id', $userId)
                ->where(function ($query) use ($time,$type) {
                    if ($type == Bill::TYPE_MONTH){
                        $query->where('year', date('Y',strtotime($time)))->where('month', date('m',strtotime($time)))->where('type',Bill::TYPE_DAY);
                    }else if ($type == Bill::TYPE_YEAR){
                        $query->where('year', date('Y',strtotime($time)))->where('type',Bill::TYPE_MONTH);
                    }
                })
                ->order('id desc')
                ->select();
            $page = page($total, $step, $page);
            $return['list'] = $data;
            $return['info'] = $totalInfo;
            $return = array_merge($return, $page);
            self::setStatusCode(self::$successCode);
            self::setMessage(self::$successMessage);
            self::setData($return);
        } catch (Exception $exception) {
            self::setStatusCode(self::$failCode);
            self::setMessage($exception->getMessage());
        }
        return ['code' => self::getStatusCode(), 'message' => self::getMessage(), 'data' => self::getData()];
    }

}